#pragma once

#include "atom.h"
using arma::imat;
#include <list>

#ifdef GRAPHENETOOLS_EXPORTS
#ifndef GRAPHENETOOLS_DLL_API
#define GRAPHENETOOLS_DLL_API __declspec(dllexport)
#endif
#else
#ifndef GRAPHENETOOLS_DLL_API
#define GRAPHENETOOLS_DLL_API __declspec(dllimport)
#endif
#endif

// This function object is used to sort a Atom::list by either the x-direction (default) or the y-direction.
class GRAPHENETOOLS_DLL_API Atom::sorter
{
  Atom::list* atoms; // This contains the reference to the list of atoms to sort.
  bool xdirection; // This contains a boolean weither the direction is x (true) or y (false).
  
public:
  sorter(); // The default constructor. Use setAtoms() to set the list to work on.
  sorter(Atom::list* const &list, bool xdir = true); // Overload constructor, set the atoms and the direction at construction.
  
  void setAtoms(Atom::list* const &list); // This setter function set a new reference to the atoms.
  
  void setDir(bool xdir); // This setter function sets the direction to either x (true) or y (false)
  
  void operator()(); // The functor operator, this will sort the referenced list.
};

// This function object is used to filter out atoms that are unwanted (as defined by the filter flags).
class GRAPHENETOOLS_DLL_API Atom::filter
{
public:
	// This enum defines the the filter flags. Use them in combination with the binary OR (|) operator.
  enum filterflags {
    floatingatoms = 0x01,	// This flag indicates that all floating atoms are filtered out.
    danglingatoms = 0x02	// This flag indicates that all dangling atoms (only one in-plane neighbour) are filtered out.
  };
  typedef char filterfield; // This typedef is supplied as a convenience to define a set of filter flags.
  static filterfield defaultFilters(); // This static function is used to et the default filterflags. Default filters all.
  
private:
  Atom::list* atoms;	// This contains the reference to the atoms that are filtered.
  imat* periodicity;
  filterfield filters;	// This contains the filters used (a char type).
  
public:
  filter(); // The default constructor, use setAtoms() and setFilters() to use the function object.
  filter(Atom::list* const &list, imat* const &per = nullptr, const filterfield &f = defaultFilters()); // Overload constructor, sets the atoms and the filters at construction.
  
  void setAtoms(Atom::list* const &list); // This setter function sets the reference to the atom list that is filtered.
  
  void setFilters(const filterfield &f); // This setter function set the filters.
  
  void operator()(); // The functor operator, this will filter the referenced atom list.
  
	// A small helper function to delete many items in a vector.
	static void erase_indices(std::vector<arma::ivec4> &atoms,std::vector<size_t>& indicesToDelete);
	// A small helper function to delete many items in a vector.
	static void erase_indices(std::vector<arma::ivec4> &atoms,std::list<size_t>& indicesToDelete);

protected:
	// A small helper function to delete many items in a vector.
	inline void erase_indices(std::list<size_t>& indicesToDelete);
	// A small helper function to delete many items in a vector.
	void erase_indices(std::vector<size_t>& indicesToDelete);
};
